/**
YASTACS system window and input events integration module D side.

License: GNU General Public License

YASTACS game
Copyright (C) 2012 Kalman Kiss, kiskami@freemail.hu

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Contact author at: kiskami@freemail.hu or
Hungary, 8900 Zalaegerszeg
Kakukkfu u 4.
*/
module input.SystemInput;

import std.stdio;

import ogreint.RenderWindow;
import ogreint.KeyEvent;
import ogreint.KeyCode;
import ogreint.MouseEvent;
import ogreint.WindowEventHandler;
import ogreint.KeyEvent;
import ogreint.KeyCode;
import ogreint.MouseEvent;
import ogreint.MouseState;

import iCore;

immutable int MAX_MOUSE_BUTTONS = 2;

class SystemInput {
public:
	// először
	void setCore(iCore core_) {
		core = core_;
		guiinput = false;
	}

	// másodszor
	void initInputEvents() {

		assert(core !is null);
		eh = new WindowEventHandler(core.rendersystem.renderwindow
									, &windowResizedCallback
									, &windowClosedCallback
									, &windowFocusChangeCallback
									, &keyPressedEventCallback
									, &keyReleasedEventCallback
									, &mouseMovedCallback
									, &mousePressedCallback
									, &mouseReleasedCallback);

		eh.setupInput();
	}

	void captureInputDevices() {
//		debug writeln("SystemInput captureInputDevices.");
		relmousex_ = 0;
		relmousey_ = 0;
		eh.captureInputDevices();
//		debug writeln("SystemInput captureInputDevices end.");
	}

	bool keyPressed(KeyCode key) {
		if (key in keytable) 
			return keytable[key];
		else
			return false;
	}

	~this () {
		debug writeln("SystemInput dtor.");
		if(eh !is null) eh.shutdown();
	}

	static SystemInput instance() {
		synchronized {
			SystemInput tmp = s;
			if(!tmp) {
				tmp = s;
				if(!tmp) {
					tmp = new SystemInput();
					s = tmp;
				}
			}
			return s;
		}
	}

	void sendInputToGui(bool s=true) {
		guiinput = s;
	}

	void windowResized(int newwidth, int newheight) {
		debug writeln("Window resized to ", newwidth, "x", newheight);
		if(guiinput)
			core.gui.windowResized(newwidth,newheight);
	}

	void windowClosed() {
//		debug writeln("SystemInput windowclosed.");
		core.endMainLoop();

	}

	void windowFocusChange() {
//		debug writeln("windowFocusChangeCallback");
		core.windowFocusChange();
	}

	void keyPressedEvent(void *keyeventobj) {
//		debug writeln("keyPressedEventCallback");
		auto ke = new KeyEvent(keyeventobj,false);
		keytable[ke.key] = true;
		if(guiinput)
			core.gui.keyPressed(keyeventobj);
//		debug writeln("Keyboard button pressed: ", ke.key);
	}

	void keyReleasedEvent(void *keyeventobj) {
//		debug writeln("keyReleasedEventCallback");
		auto ke = new KeyEvent(keyeventobj,false);
		keytable[ke.key] = false;
		if(guiinput)
			core.gui.keyReleased(keyeventobj);
//		debug writeln("Keyboard button released: ", ke.key);
	}

	void mouseMoved(void *mouseeventobj) {
//		debug writeln("mouseMovedCallback");

		auto me = new MouseEvent(mouseeventobj,false);
		auto state = me.state();
		mousex_ = state.X().abs();
		mousey_ = state.Y().abs();
		relmousex_ = state.X().rel();
		relmousey_ = state.Y().rel();
		if(guiinput)
			core.gui.mouseMoved(mouseeventobj);
//		debug writeln("Mouse state: x=", mousex_, " y=", mousey_
//					  , ", relx=", relmousex_, ", rely=", relmousey_);
	}

	void mousePressed(void *mouseeventobj, int buttonId) {
		if(buttonId>=MAX_MOUSE_BUTTONS) return;
//		debug writeln("Mouse button pressed: ", buttonId);
		mousebuttons[buttonId] = true;
		if(guiinput)
			core.gui.mousePressed(mouseeventobj,buttonId);
	}

	void mouseReleased(void *mouseeventobj, int buttonId) {
//		debug writeln("Mouse button released: ", buttonId);
		mousebuttons[buttonId] = false;
		if(guiinput)
			core.gui.mouseReleased(mouseeventobj,buttonId);
	}

	@property bool leftmousebtnpressed() { return mousebuttons[0]; }
	@property bool rightmousebtnpressed() { return mousebuttons[1]; }

	@property int mousex() { return mousex_; }
	@property int mousey() { return mousey_; }
	@property int relmousex() { return relmousex_; }
	@property int relmousey() { return relmousey_; }

private:

	static SystemInput s;

	iCore core;
	WindowEventHandler eh;

	bool[int] keytable;
	int mousex_, mousey_,
//		lastmousex, lastmousey,
		relmousex_, relmousey_;
	bool[MAX_MOUSE_BUTTONS] mousebuttons;

	bool guiinput;
};

//
// Global callbacks for Ogre-Window/input events
//

extern (C++) {
	void windowResizedCallback(int newwidth, int newheight) {
//		debug writeln("windowResizedCallback");
		SystemInput.instance().windowResized(newwidth, newheight);
	}

	void windowClosedCallback() {
		debug writeln("windowClosedCallback");
		SystemInput.instance().windowClosed();

	}

	void windowFocusChangeCallback() {
		debug writeln("input windowFocusChangeCallback");
		SystemInput.instance().windowFocusChange();
	}

	void keyPressedEventCallback(void *keyeventobj) {
		SystemInput.instance().keyPressedEvent(keyeventobj);
	}

	void keyReleasedEventCallback(void *keyeventobj) {
		SystemInput.instance().keyReleasedEvent(keyeventobj);
	}

	void mouseMovedCallback(void *mouseeventobj) {
		SystemInput.instance().mouseMoved(mouseeventobj);
	}

	void mousePressedCallback(void *mouseeventobj, int buttonId) {
		SystemInput.instance().mousePressed(mouseeventobj, buttonId);
	}

	void mouseReleasedCallback(void *mouseeventobj, int buttonId) {
		SystemInput.instance().mouseReleased(mouseeventobj, buttonId);
	}
}
